home *** CD-ROM | disk | FTP | other *** search
/ Collection of Tools & Utilities / Collection of Tools and Utilities.iso / edit / mg2a_src.zip / LINE.C < prev    next >
C/C++ Source or Header  |  1988-08-23  |  17KB  |  610 lines

  1. /*
  2.  *        Text line handling.
  3.  * The functions in this file
  4.  * are a general set of line management
  5.  * utilities. They are the only routines that
  6.  * touch the text. They also touch the buffer
  7.  * and window structures, to make sure that the
  8.  * necessary updating gets done. There are routines
  9.  * in this file that handle the kill buffer too.
  10.  * It isn't here for any good reason.
  11.  *
  12.  * Note that this code only updates the dot and
  13.  * mark values in the window list. Since all the code
  14.  * acts on the current window, the buffer that we
  15.  * are editing must be being displayed, which means
  16.  * that "b_nwnd" is non zero, which means that the
  17.  * dot and mark values in the buffer headers are
  18.  * nonsense.
  19.  */
  20. #include    "def.h"
  21.  
  22. /* number of bytes member is from start of structure type    */
  23. /* should be computed at compile time                */
  24.  
  25. #ifndef OFFSET
  26. #define OFFSET(type,member) ((char *)&(((type *)0)->member)-(char *)((type *)0))
  27. #endif
  28.  
  29. #ifndef NBLOCK
  30. #define NBLOCK    16            /* Line block chunk size    */
  31. #endif
  32.  
  33. #ifndef KBLOCK
  34. #define KBLOCK    256            /* Kill buffer block size.    */
  35. #endif
  36.  
  37. static char    *kbufp    = NULL;        /* Kill buffer data.        */
  38. static RSIZE    kused    = 0;        /* # of bytes used in KB.    */
  39. static RSIZE    ksize    = 0;        /* # of bytes allocated in KB.    */
  40. static RSIZE    kstart    = 0;        /* # of first used byte in KB.    */
  41.  
  42. /*
  43.  * This routine allocates a block of memory large enough to hold a LINE
  44.  * containing "used" characters. The block is rounded up to whatever
  45.  * needs to be allocated. (use lallocx for lines likely to grow.)
  46.  * Return a pointer to the new block, or NULL if there isn't
  47.  * any memory left. Print a message in the message line if no space.
  48.  */
  49. LINE *
  50. lalloc(used) register int used; {
  51.     register LINE    *lp;
  52.     register int    size;
  53.  
  54.     /* any padding at the end of the structure is used */
  55.     if((size = used + OFFSET(LINE, l_text[0])) < sizeof(LINE))
  56.         size = sizeof(LINE);
  57. #ifdef MALLOCROUND
  58.     MALLOCROUND(size);    /* round up to a size optimal to malloc */
  59. #endif
  60.     if((lp = (LINE *)malloc((unsigned)size)) == NULL) {
  61.         ewprintf("Can't get %d bytes", size);
  62.         return (LINE *)NULL;
  63.     }
  64.     lp->l_size = size - OFFSET(LINE, l_text[0]);
  65.     lp->l_used = used;
  66.     return lp;
  67. }
  68.  
  69. /*
  70.  * Like lalloc, only round amount desired up because this line will
  71.  * probably grow.  We always make room for at least one more char.
  72.  * (thus making 0 not a special case anymore.)
  73.  */
  74. LINE *
  75. lallocx(used)
  76. int used;
  77. {
  78.     register int size;
  79.     register LINE *lp;
  80.  
  81.     size = (NBLOCK+used) & ~(NBLOCK-1);
  82.     if((lp = lalloc(size)) != NULL) lp->l_used = used;
  83.     return lp;
  84. }
  85.  
  86. /*
  87.  * Delete line "lp". Fix all of the
  88.  * links that might point at it (they are
  89.  * moved to offset 0 of the next line.
  90.  * Unlink the line from whatever buffer it
  91.  * might be in. Release the memory. The
  92.  * buffers are updated too; the magic conditions
  93.  * described in the above comments don't hold
  94.  * here.
  95.  */
  96. VOID
  97. lfree(lp) register LINE *lp; {
  98.     register BUFFER *bp;
  99.     register WINDOW *wp;
  100.  
  101.     for(wp = wheadp; wp != NULL; wp = wp->w_wndp) {
  102.         if (wp->w_linep == lp)
  103.             wp->w_linep = lp->l_fp;
  104.         if (wp->w_dotp    == lp) {
  105.             wp->w_dotp  = lp->l_fp;
  106.             wp->w_doto  = 0;
  107.         }
  108.         if (wp->w_markp == lp) {
  109.             wp->w_markp = lp->l_fp;
  110.             wp->w_marko = 0;
  111.         }
  112.     }
  113.     for(bp = bheadp; bp != NULL; bp = bp->b_bufp) {
  114.         if (bp->b_nwnd == 0) {
  115.             if (bp->b_dotp    == lp) {
  116.                 bp->b_dotp = lp->l_fp;
  117.                 bp->b_doto = 0;
  118.             }
  119.             if (bp->b_markp == lp) {
  120.                 bp->b_markp = lp->l_fp;
  121.                 bp->b_marko = 0;
  122.             }
  123.         }
  124.     }
  125.     lp->l_bp->l_fp = lp->l_fp;
  126.     lp->l_fp->l_bp = lp->l_bp;
  127.     free((char *) lp);
  128. }
  129.  
  130. /*
  131.  * This routine gets called when
  132.  * a character is changed in place in the
  133.  * current buffer. It updates all of the required
  134.  * flags in the buffer and window system. The flag
  135.  * used is passed as an argument; if the buffer is being
  136.  * displayed in more than 1 window we change EDIT to
  137.  * HARD. Set MODE if the mode line needs to be
  138.  * updated (the "*" has to be set).
  139.  */
  140. VOID
  141. lchange(flag) register int flag; {
  142.     register WINDOW *wp;
  143.  
  144.     if ((curbp->b_flag&BFCHG) == 0) {    /* First change, so    */
  145.         flag |= WFMODE;            /* update mode lines.    */
  146.         curbp->b_flag |= BFCHG;
  147.     }
  148.     for(wp = wheadp; wp != NULL; wp = wp->w_wndp) {
  149.         if (wp->w_bufp == curbp) {
  150.             wp->w_flag |= flag;
  151.             if(wp != curwp) wp->w_flag |= WFHARD;
  152.         }
  153.     }
  154. }
  155.  
  156. /*
  157.  * Insert "n" copies of the character "c"
  158.  * at the current location of dot. In the easy case
  159.  * all that happens is the text is stored in the line.
  160.  * In the hard case, the line has to be reallocated.
  161.  * When the window list is updated, take special
  162.  * care; I screwed it up once. You always update dot
  163.  * in the current window. You update mark, and a
  164.  * dot in another window, if it is greater than
  165.  * the place where you did the insert. Return TRUE
  166.  * if all is well, and FALSE on errors.
  167.  */
  168. linsert(n, c)
  169. int n;
  170. {
  171.     register char    *cp1;
  172.     register char    *cp2;
  173.     register LINE    *lp1;
  174.     LINE        *lp2;
  175.     LINE        *lp3;
  176.     register int    doto;
  177.     register RSIZE    i;
  178.     WINDOW        *wp;
  179.  
  180.     lchange(WFEDIT);
  181.     lp1 = curwp->w_dotp;            /* Current line        */
  182.     if (lp1 == curbp->b_linep) {        /* At the end: special    */
  183.             /* (now should only happen in empty buffer    */
  184.         if (curwp->w_doto != 0) {
  185.             ewprintf("bug: linsert");
  186.             return FALSE;
  187.         }
  188.         if ((lp2=lallocx(n)) == NULL) /* Allocate new line */
  189.             return FALSE;
  190.         lp3 = lp1->l_bp;        /* Previous line    */
  191.         lp3->l_fp = lp2;        /* Link in        */
  192.         lp2->l_fp = lp1;
  193.         lp1->l_bp = lp2;
  194.         lp2->l_bp = lp3;
  195.         for (i=0; i<n; ++i)
  196.             lp2->l_text[i] = c;
  197.         for(wp = wheadp; wp != NULL; wp = wp->w_wndp) {
  198.             if (wp->w_linep == lp1)
  199.                 wp->w_linep = lp2;
  200.             if (wp->w_dotp == lp1)
  201.                 wp->w_dotp = lp2;
  202.             if (wp->w_markp == lp1)
  203.                 wp->w_markp = lp2;
  204.         }
  205.         /*NOSTRICT*/
  206.         curwp->w_doto = n;
  207.         return TRUE;
  208.     }
  209.     doto = curwp->w_doto;            /* Save for later.    */
  210.     /*NOSTRICT (2) */
  211.     if (lp1->l_used+n > lp1->l_size) {    /* Hard: reallocate    */
  212.         if ((lp2=lallocx(lp1->l_used+n)) == NULL)
  213.             return FALSE;
  214.         cp1 = &lp1->l_text[0];
  215.         cp2 = &lp2->l_text[0];
  216.         while (cp1 != &lp1->l_text[doto])
  217.             *cp2++ = *cp1++;
  218.         /*NOSTRICT*/
  219.         cp2 += n;
  220.         while (cp1 != &lp1->l_text[lp1->l_used])
  221.             *cp2++ = *cp1++;
  222.         lp1->l_bp->l_fp = lp2;
  223.         lp2->l_fp = lp1->l_fp;
  224.         lp1->l_fp->l_bp = lp2;
  225.         lp2->l_bp = lp1->l_bp;
  226.         free((char *) lp1);
  227.     } else {                /* Easy: in place    */
  228.         lp2 = lp1;            /* Pretend new line    */
  229.         /*NOSTRICT*/
  230.         lp2->l_used += n;
  231.         cp2 = &lp1->l_text[lp1->l_used];
  232.  
  233.         cp1 = cp2-n;
  234.         while (cp1 != &lp1->l_text[doto])
  235.             *--cp2 = *--cp1;
  236.     }
  237.     for (i=0; i<n; ++i)            /* Add the characters    */
  238.         lp2->l_text[doto+i] = c;
  239.  
  240.     for(wp = wheadp; wp != NULL; wp = wp->w_wndp) {
  241.         if (wp->w_linep == lp1)
  242.             wp->w_linep = lp2;
  243.         if (wp->w_dotp == lp1) {
  244.             wp->w_dotp = lp2;
  245.             if (wp==curwp || wp->w_doto>doto)
  246.                 /*NOSTRICT*/
  247.                 wp->w_doto += n;
  248.         }
  249.         if (wp->w_markp == lp1) {
  250.             wp->w_markp = lp2;
  251.             if (wp->w_marko > doto)
  252.                 /*NOSTRICT*/
  253.                 wp->w_marko += n;
  254.         }
  255.     }
  256.     return TRUE;
  257. }
  258.  
  259. /*
  260.  * Insert a newline into the buffer
  261.  * at the current location of dot in the current
  262.  * window.  The funny ass-backwards way is no longer used.
  263.  */
  264. lnewline()
  265. {
  266.     register LINE    *lp1;
  267.     register LINE    *lp2;
  268.     register int    doto;
  269.     register int    nlen;
  270.     WINDOW        *wp;
  271.  
  272.     lchange(WFHARD);
  273.     lp1  = curwp->w_dotp;            /* Get the address and    */
  274.     doto = curwp->w_doto;            /* offset of "."    */
  275.     if(doto == 0) {                /* avoid unnessisary copying */
  276.         if((lp2 = lallocx(0)) == NULL)    /* new first part    */
  277.             return FALSE;
  278.         lp2->l_bp = lp1->l_bp;
  279.         lp1->l_bp->l_fp = lp2;
  280.         lp2->l_fp = lp1;
  281.         lp1->l_bp = lp2;
  282.         for(wp = wheadp; wp!=NULL; wp = wp->w_wndp)
  283.             if(wp->w_linep == lp1) wp->w_linep = lp2;
  284.         return    TRUE;
  285.     }
  286.     nlen = llength(lp1) - doto;        /* length of new part    */
  287.     if((lp2=lallocx(nlen)) == NULL)        /* New second half line */
  288.         return FALSE;
  289.     if(nlen!=0) bcopy(&lp1->l_text[doto], &lp2->l_text[0], nlen);
  290.     lp1->l_used = doto;
  291.     lp2->l_bp = lp1;
  292.     lp2->l_fp = lp1->l_fp;
  293.     lp1->l_fp = lp2;
  294.     lp2->l_fp->l_bp = lp2;
  295.     for(wp = wheadp; wp != NULL; wp = wp->w_wndp) { /* Windows    */
  296.         if (wp->w_dotp == lp1 && wp->w_doto >= do